/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cipher;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Adamiczu
 */
public class CipherInputStream extends FilterInputStream {
    byte[] sBox;
    byte[] kBox;
    byte[] key = {24,21,99,(byte)128,(byte)255,(byte)155,20,1};
    
    public CipherInputStream(InputStream in) {
        super(in);
        sBox = new byte[256];
        kBox = new byte[256];
        initialization();
        scrambling();
    }
    
    private void initialization() {
        for(int i = 0, j = 0; i < 256; i++) {
            if(j % key.length == 0 && j != 0) {
                j = 0;
            }
            sBox[i] = (byte) i;
            kBox[i] = key[j];
            j++;
        }
    }
    
    private void scrambling() {
        int j = 0;
        for(int i = 0; i < 255; i++) {
            j = (j + sBox[i] & 0xFF + kBox[i] & 0xFF) % 256;
            byte temp = sBox[i];
            sBox[i] = sBox[j];
            sBox[j] = temp;
        }
    }
    
    private byte generationOfPseudoRandomNumbers(int messageSize) {
        int i = 0; 
        int j = 0; 
        for(int k = 0; k < messageSize - 1; k++) {
            i = (i + 1) % 256;
            j = (j + sBox[i] & 0xFF) % 256;
            byte temp = sBox[i];
            sBox[i] = sBox[j];
            sBox[j] = temp;
        }
        
        return sBox[(sBox[i] & 0xFF + sBox[j] & 0xFF) % 256];
    }
    
    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        if(super.in.read(b, off, len) == -1) {
            return -1;
        }
        else {
            int cipheredMessageSize = b.length;
            byte keyStream = generationOfPseudoRandomNumbers(cipheredMessageSize);

            for(int i = 0; i < cipheredMessageSize; i++) {
                b[i] = (byte) (b[i] ^ keyStream);
            }

            return cipheredMessageSize;
        }
    }
}
